package com.sgzn.sgpay.service.impl;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.sgzn.sgpay.enums.*;
import com.sgzn.sgpay.exception.SgpayException;
import com.sgzn.sgpay.model.request.*;
import com.sgzn.sgpay.model.response.CurrentPageInfo;
import com.sgzn.sgpay.model.response.DeviceStatisticDto;
import com.sgzn.sgpay.model.response.SgsResultResponse;
import com.sgzn.sgpay.model.response.result.DevicePageListResult;
import com.sgzn.sgpay.model.response.vo.DeviceInfoVo;
import com.sgzn.sgpay.model.response.vo.DeviceVo;
import com.sgzn.sgpay.persistence.dao.TDeviceMapper;
import com.sgzn.sgpay.persistence.domain.TDevice;
import com.sgzn.sgpay.persistence.domain.TDeviceExample;
import com.sgzn.sgpay.persistence.domain.TShop;
import com.sgzn.sgpay.persistence.manager.DeviceDaoManager;
import com.sgzn.sgpay.persistence.manager.ShopDaoManager;
import com.sgzn.sgpay.service.SgsDeviceOperateLogService;
import com.sgzn.sgpay.service.SgsDevicePresentLogService;
import com.sgzn.sgpay.service.SgsDeviceService;
import com.sgzn.sgpay.service.converter.AssembleSgsCommonHandle;
import com.sgzn.sgpay.service.support.DeviceStatHandler;
import com.sgzn.sgpay.service.support.SgsResponseUtil;
import com.sgzn.sgpay.util.ArgsUtils;
import com.sgzn.sgpay.util.PageCalculator;
import com.sgzn.sgpay.util.TranslateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by xxjs-gd-llf
 * DATETIME:2018/4/6 15:06
 * Description:
 */
@Service
@Slf4j
public class SgsDeviceServiceImpl implements SgsDeviceService{

    @Resource
    private TDeviceMapper tDeviceMapper;

    @Resource
    private ShopDaoManager shopDaoManager;

    @Resource
    private DeviceStatHandler deviceStatHandler;

    @Resource
    private DeviceDaoManager deviceDaoManager;

    @Resource
    private AssembleSgsCommonHandle assembleSgsCommonHandle;

    @Resource
    private SgsDevicePresentLogService sgsDevicePresentLogService;

    @Resource
    private SgsDeviceOperateLogService  sgsDeviceOperateLogService;

    /**
     * 最大场地编号
     */
    private static int MAX_SITE_NUM = 16;

    /**
     * 添加设备
     */
    @Override
    @Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public SgsResultResponse<String> addDevice(SgsDeviceAddRequest request){
        List<TDevice> exist = deviceDaoManager.getTDeviceList(request.getDeviceId());
        log.info("SgsDeviceServiceImpl addDevice exist:{}", exist);
        ArgsUtils.isEmpty(exist, SgsResponseCode.C_DUPLICATE_DEVICE_EXIST.getResponseCode(),
                SgsResponseCode.C_DUPLICATE_DEVICE_EXIST.getResponseDesc());

        //设备新增操作记录
        addDeviceOpraRecode(request);
        //入库
        TDevice tDevice = new TDevice();
        tDevice.setDeviceId(request.getDeviceId());
        tDevice.setDeviceType(request.getDeviceType());
        tDevice.setDeviceName(DeviceType.getDescByCode(request.getDeviceType()) + request.getSiteNum());
        tDevice.setShopId(request.getShopId());
        tDevice.setSiteNum(request.getSiteNum());
        tDevice.setState(EnumDeviceState.OFFLINE.getStateCode() );//初始化为不可用
        tDevice.setMerchantId(request.getMchId());
        tDevice.setPrice(Integer.valueOf(request.getPrice()));
        tDevice.setCreatedAt(request.getReqTime());
        tDevice.setUpdatedAt(request.getReqTime());
        int num = tDeviceMapper.insertSelective(tDevice);
        if (num >= 1) {
            return SgsResponseUtil.INSTANCE.success(ReturnResultState.SUCCESS.getCode());
        } else {
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C503.getResponseCode(),SgsResponseCode.C503.getResponseDesc(), ReturnResultState.FAIL.getCode());
        }
    }

    @Override
    @Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public SgsResultResponse<String> deleteDevice(SgsDeviceDeleteRequest request) {
        //执行删除
        TDeviceExample example = new TDeviceExample();
        TDeviceExample.Criteria criteria = example.createCriteria();
        criteria.andDeviceIdIn(request.getIds());
        int num = 0 ;
        try{
            num =  tDeviceMapper.deleteByExample(example);
            if(num >0){
                //记录设备操作记录
                SgsDeviceOperateLogAddRequest sgsDeviceOperateLogAddRequest = new SgsDeviceOperateLogAddRequest();
                sgsDeviceOperateLogAddRequest.setDeviceId(request.getIds().get(0));
                sgsDeviceOperateLogAddRequest.setOperateType(DeviceOperateTypeEnum.UNBIND.getCode());
                sgsDeviceOperateLogAddRequest.setOperateContent(DeviceOperateTypeEnum.UNBIND.getDesc());
                sgsDeviceOperateLogAddRequest.setMchId(request.getMchId());
                this.sgsDeviceOperateLogService.add(sgsDeviceOperateLogAddRequest);
            }
        }catch (DataAccessException e) {
            log.error("插入响应流水日志异常.{}", e);
        }
        if (num >= 1) {
            return SgsResponseUtil.INSTANCE.success(ReturnResultState.SUCCESS.getCode());
        } else {
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C503.getResponseCode(),SgsResponseCode.C503.getResponseDesc(), ReturnResultState.FAIL.getCode());
        }
    }

    /**
     * 查询设备状态
     * @param request
     */
    @Override
    public SgsResultResponse<DeviceInfoVo> queryDeviceInfo(SgsDeviceQueryRequest request){
        //校验token并返回商户ID
        List<TDevice> tDevices = deviceDaoManager.getTDeviceList(request.getDeviceId());
        if (CollectionUtils.isEmpty(tDevices)) {
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseCode(),SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseDesc());
        }
        TDevice tDevice = tDevices.get(0);
        TShop tShop = shopDaoManager.getTShop(tDevice.getShopId());
        return SgsResponseUtil.INSTANCE.success(assemebleDeviceInfoVo(tDevice, tShop));
    }

    /**
     * 查询设备状态
     * @param request
     */
    @Override
    public SgsResultResponse<DeviceInfoVo> queryMchDeviceInfo(SgsDeviceMchQueryRequest request){
        //校验token并返回商户ID
        List<TDevice> tDevices = deviceDaoManager.getTDeviceList(request.getDeviceId());
        if (CollectionUtils.isEmpty(tDevices)) {
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseCode(),SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseDesc());
        }
        TDevice tDevice = tDevices.get(0);
        TShop tShop = shopDaoManager.getTShop(tDevice.getShopId());
        return SgsResponseUtil.INSTANCE.success(assemebleDeviceInfoVo(tDevice, tShop));
    }


    @Override
    @Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public SgsResultResponse<String> updateDevice(SgsDeviceUpdateRequest request) {
        TDevice record = new TDevice();
        record.setDeviceName(DeviceType.getDescByCode(request.getDeviceType()) + request.getSiteNum());
        record.setShopId(request.getShopId());
        record.setState(request.getState());
        record.setSiteNum(request.getSiteNum());
        record.setPrice(Integer.valueOf(request.getPrice()));
        record.setUpdatedBy(request.getMchId());
        record.setUpdatedAt(request.getReqTime());
        record.setMerchantId(request.getMchId());

        TDeviceExample example = new TDeviceExample();
        TDeviceExample.Criteria criteria = example.createCriteria();
        criteria.andDeviceIdEqualTo(request.getDeviceId());

        int num = 0 ;
        try{
            num =  tDeviceMapper.updateByExampleSelective(record, example);
        }catch (DataAccessException e) {
            log.error("更新设备信息异常.{}", e);
        }

        if (num >= 1) {
            return SgsResponseUtil.INSTANCE.success(ReturnResultState.SUCCESS.getCode());
        } else {
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C503.getResponseCode(),SgsResponseCode.C503.getResponseDesc(), ReturnResultState.FAIL.getCode());
        }
    }


    @Override
    @Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public SgsResultResponse<String> updateDeviceTcp(SgsDeviceUpdateTcpRequest request) {
        TDevice record = new TDevice();
        record.setDeviceName(DeviceType.getDescByCode(request.getDeviceType()) + request.getSiteNum());
        record.setShopId(request.getShopId());
        record.setState(request.getState());
        record.setSiteNum(request.getSiteNum());
        record.setPrice(Integer.valueOf(request.getPrice()));
        record.setUpdatedAt(request.getReqTime());

        TDeviceExample example = new TDeviceExample();
        TDeviceExample.Criteria criteria = example.createCriteria();
        criteria.andDeviceIdEqualTo(request.getDeviceId());

        int num = 0 ;
        try{
            num =  tDeviceMapper.updateByExampleSelective(record, example);
        }catch (DataAccessException e) {
            log.error("更新设备信息异常.{}", e);
        }

        if (num >= 1) {
            return SgsResponseUtil.INSTANCE.success(ReturnResultState.SUCCESS.getCode());
        } else {
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C503.getResponseCode(),SgsResponseCode.C503.getResponseDesc(), ReturnResultState.FAIL.getCode());
        }
    }


    /**
     * 更新设备状态
     */
    @Override
    public SgsResultResponse<String> updateDeviceStateById(String deviceId,String deviceState){
        TDevice record = new TDevice();
        record.setState( deviceState );

        TDeviceExample example = new TDeviceExample();
        TDeviceExample.Criteria criteria = example.createCriteria();
        criteria.andDeviceIdEqualTo(deviceId);
        int num= tDeviceMapper.updateByExampleSelective(record,example);
        if (num >= 1) {
            return SgsResponseUtil.INSTANCE.success(ReturnResultState.SUCCESS.getCode());
        } else {
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C503.getResponseCode(),SgsResponseCode.C503.getResponseDesc(), ReturnResultState.FAIL.getCode());
        }
    }



    /**
     * 设备分页查询
     * @param request
     * @return
     */
    @Override
    public SgsResultResponse<DevicePageListResult> queryPageList(SgsDeviceQueryPageRequest request) {
        TDeviceExample example = this.getTDeviceExampleByPage(request);
        int totalCount = this.tDeviceMapper.countByExample(example);//获取总数
        CurrentPageInfo pageInfo = PageCalculator.getPageInfo(totalCount, request.getPageQueryParam().getPageSize(),
                request.getPageQueryParam().getCurrentPage());

        StringBuffer clause = new StringBuffer();
        //加上起始和结束行号进行列表查询
        clause.append("shop_id, updated_at desc ");
        clause.append("limit ").append(pageInfo.getStartIndex()).
                append(",").append(pageInfo.getPageSize());
        example.setOrderByClause(clause.toString());
        List<TDevice> list = tDeviceMapper.selectByExample(example);
        //组装门店名称集合<shopId,shopName>
        Map<String,String> shopMap = this.getShopMap(list);
        //组装设备统计数据
        DeviceStatisticDto statisticDto = deviceStatHandler.getDeviceStatisData(request.getMchId(),pageInfo.getCurrentPage());
        //组装最终结果
        DevicePageListResult result = assembleDeviceVoList(list,shopMap,statisticDto,pageInfo);
        return SgsResponseUtil.INSTANCE.success(result);
    }

    /**
     * 查询可选场地编码
     * @param request
     * @return
     */
    @Override
    public SgsResultResponse<List<String>> queryAvailCode(SgsDeviceAvailCodeQueryRequest request) {
        List<String> resultList = new ArrayList<>();//结果列表
        HashMap<String,String> siteMap = new HashMap<>();//已使用的场地编号
        TDeviceExample example = new TDeviceExample();
        TDeviceExample.Criteria cra = example.createCriteria();
        cra.andShopIdEqualTo(request.getShopId());
        List<TDevice> list = tDeviceMapper.selectByExample(example);
        if(CollectionUtils.isNotEmpty(list)){
            for(TDevice item : list){
                String siteNum = item.getSiteNum();
                siteMap.put(siteNum,siteNum);
            }
        }
        //过滤掉已使用的编号
        for(int i = 1; i <= MAX_SITE_NUM ;i++){
            String iStr = String.valueOf(i);
            if(!siteMap.containsKey(String.valueOf(i))){
                resultList.add(iStr);
            }
        }
        return SgsResponseUtil.INSTANCE.success(resultList);
    }


    /**
     * 设备绑定礼品
     * @param request
     * @return
     */
    @Override
    public SgsResultResponse<String> bindPresent(SgsDeviceBindPresentRequest request){

        //根据DeviceId获取设备信息
        TDevice deviceInfo = this.deviceDaoManager.getTDevice(request.getDeviceId());
        if (deviceInfo == null){
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseCode(),SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseDesc());
        }

        //更新设备绑定的礼品信息
        TDevice tDevice = new TDevice();
        tDevice.setPresentBalance( Integer.parseInt(request.getPresentNumber() ));
        tDevice.setPresentId(request.getPresentId());
        TDeviceExample tDeviceExample = new TDeviceExample();
        TDeviceExample.Criteria criteria = tDeviceExample.createCriteria();
        criteria.andDeviceIdEqualTo(deviceInfo.getDeviceId() );
        int num = tDeviceMapper.updateByExampleSelective(tDevice,tDeviceExample);



        //新增设备礼品记录
        SgsAddDevicePresentLogRequest sgsAddDevicePresentLogRequest = new SgsAddDevicePresentLogRequest();
        assembleSgsCommonHandle.assemble(request,sgsAddDevicePresentLogRequest);
        sgsAddDevicePresentLogRequest.setDeviceId( request.getDeviceId());
        sgsAddDevicePresentLogRequest.setMerchantId(request.getMchId());
        sgsAddDevicePresentLogRequest.setShopId(deviceInfo.getShopId());
        sgsAddDevicePresentLogRequest.setPresentId( request.getPresentId() );
        sgsAddDevicePresentLogRequest.setOperNumber(request.getPresentNumber());
        sgsAddDevicePresentLogRequest.setOperType(EnumDevicePresentLogTradeMark.INCREASE.getCode()); //增加
        SgsResultResponse<String> stringSgsResultResponse = sgsDevicePresentLogService.addDevicePresentLog( sgsAddDevicePresentLogRequest );
        if (stringSgsResultResponse == null ){
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C503.getResponseCode(),SgsResponseCode.C503.getResponseDesc());
        }else {
            return SgsResponseUtil.INSTANCE.success(ReturnResultState.SUCCESS.getCode());
        }

    }

    /**
     * 查询设备状态
     * @param request
     */
    @Override
    public SgsResultResponse<TDevice> queryDevicePrice(SgsDeviceQueryRequest request){
        //查询设备
        List<TDevice> tDevices = deviceDaoManager.getTDeviceList(request.getDeviceId());
        if (CollectionUtils.isEmpty(tDevices)) {
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseCode(),SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseDesc());
        }
        TDevice tDevice = tDevices.get(0);
        return SgsResponseUtil.INSTANCE.success(tDevice);
    }

    /**
     * 组装设备详细信息
     * @param tDevice
     * @param tShop
     */
    private DeviceInfoVo assemebleDeviceInfoVo(TDevice tDevice, TShop tShop) {
        DeviceInfoVo deviceInfoVo = new DeviceInfoVo();
        if (tDevice != null) {
            deviceInfoVo.setDeviceId(tDevice.getDeviceId());
            deviceInfoVo.setDeviceName(tDevice.getDeviceName());
            deviceInfoVo.setState(tDevice.getState());
            deviceInfoVo.setDeviceType(tDevice.getDeviceType());
            deviceInfoVo.setShopId(tDevice.getShopId());
            deviceInfoVo.setSiteNum(tDevice.getSiteNum());
            deviceInfoVo.setMerchantId(tDevice.getMerchantId());
            deviceInfoVo.setPrice(String.valueOf(tDevice.getPrice()));
            deviceInfoVo.setShopName(tShop.getShopName());
            deviceInfoVo.setPresentId(tDevice.getPresentId());
            if (tDevice.getPresentBalance() != null ) {
                deviceInfoVo.setPresentStock(tDevice.getPresentBalance().toString()); //空的字符串不能转为.toString()需要用工具类
            }


        }
        return deviceInfoVo;
    }

    /**
     * 获取单页门店Map
     * @param list
     * @return
     */
    private Map<String,String> getShopMap(List<TDevice> list){
        Map<String,String> resultMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(list)){
            List<String> shopIdList = new ArrayList<>();
            for(TDevice item :list){
                shopIdList.add(item.getShopId());
            }
            List<TShop> shopList = shopDaoManager.getTShopList(shopIdList);
            if(CollectionUtils.isNotEmpty(shopIdList)){
                for (TShop item : shopList){
                    resultMap.put(item.getShopId(),item.getShopName());
                }
            }
        }
        return resultMap;
    }

    /**
     * 设备新增操作记录
     * @param request
     */
    private void addDeviceOpraRecode(SgsDeviceAddRequest request) {
        SgsDeviceOperLogRecordRequest targetReq = new SgsDeviceOperLogRecordRequest();
        assembleSgsCommonHandle.assemble(request, targetReq);
        targetReq.setMchId(request.getMchId());
        targetReq.setDeviceId(request.getDeviceId());
        targetReq.setDeviceName(DeviceType.getDescByCode(request.getDeviceType()) + request.getSiteNum());
        targetReq.setShopId(request.getShopId());
        targetReq.setOperateType(DeviceOperateTypeEnum.REGISTER.getCode());
        targetReq.setOperateContent(DeviceOperateTypeEnum.REGISTER.getDesc());
        SgsResultResponse<String> resp = sgsDeviceOperateLogService.add(targetReq);
        if(TranslateUtil.isSuccessAbs(resp.getErrorCode()) && resp.getResult() != null){
            log.info("设备新增操作记录 success");
        } else {
            log.info("设备新增操作记录  fail:{}", resp);
            throw new SgpayException(SgsResponseCode.DEVICE_RECORD_FAIL.getResponseCode(),
                    SgsResponseCode.DEVICE_RECORD_FAIL.getResponseDesc());
        }
    }

    /**
     * 组装结果
     * @param deviceList
     * @param shopMap
     */
    private DevicePageListResult assembleDeviceVoList(List<TDevice> deviceList, Map<String,String> shopMap,
                                                      DeviceStatisticDto statisticDto, CurrentPageInfo pageInfo) {
        DevicePageListResult result = new DevicePageListResult();
        List<DeviceVo> voList = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(deviceList)){
            //组装列表
            for (TDevice item : deviceList) {
                DeviceVo vo = new DeviceVo();
                vo.setDeviceId(item.getDeviceId());
                vo.setDeviceName(item.getDeviceName());
                vo.setShopId(item.getShopId());
                vo.setShopName(shopMap.get(item.getShopId()));
                vo.setMerchantId(item.getMerchantId());
                vo.setState(item.getState());
                vo.setPrice(String.valueOf(item.getPrice()));
                voList.add(vo);
            }
        }
        result.setDeviceList(voList);
        //组装统计数据
        if(statisticDto != null){
            result.setAllNum(statisticDto.getAllNum());
            result.setOnlineNum(statisticDto.getOnlineNum());
            result.setOfflineNum(statisticDto.getOfflineNum());
            result.setShopNum(statisticDto.getShopNum());
        }
        //组装分页信息
        result.setCurrentPage(pageInfo.getCurrentPage());
        result.setPageSize(pageInfo.getPageSize());
        result.setTotalCount(pageInfo.getTotalCount());
        result.setTotalPage(pageInfo.getTotalPage());
        return result;
    }


    /**
     * 获取查询对象
     * @param request
     * @return
     */
    private TDeviceExample getTDeviceExampleByPage(SgsDeviceQueryPageRequest request){
        TDeviceExample countExample = new TDeviceExample();
        TDeviceExample.Criteria cra = countExample.createCriteria();
        if(StringUtils.isNotBlank(request.getMerchantId())){
            cra.andMerchantIdEqualTo(request.getMerchantId());//根据商户号
        }
        if(StringUtils.isNotBlank(request.getDeviceId())){
            cra.andDeviceIdEqualTo(request.getDeviceId());
        }
        if(StringUtils.isNotBlank(request.getDeviceName())){
            cra.andDeviceNameLike(request.getDeviceName());
        }
        if(StringUtils.isNotBlank(request.getShopId())){
            cra.andShopIdEqualTo(request.getShopId());
        }
        if(StringUtils.isNotBlank(request.getState())){
            cra.andStateEqualTo(request.getState());
        }
        return countExample;
    }


}
